package com.ruoyi.project.product.controller;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.digest.HMac;
import cn.hutool.crypto.digest.HmacAlgorithm;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.product.domain.*;
import com.ruoyi.project.product.service.*;
import com.ruoyi.project.system.service.ISysDictDataService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 试剂订单记录Controller
 *
 * @author taney
 * @date 2020-11-23
 */
@AllArgsConstructor
@RestController
@RequestMapping("/product/order")
public class InsReagentOrderController extends BaseController {

    private final IInsReagentOrderService iInsReagentOrderService;
    private final IInsReagentOrderListService iInsReagentOrderListService;
    private final IInsReagentOrderListDetailService iInsReagentOrderListDetailService;
    private final IInsReagentFormService iInsReagentFormService;
    private final IInsReagentFormDetailService iInsReagentFormDetailService;
    private final ISysDictDataService iSysDictDataService;
    private final IInsReagentBoxService iInsReagentBoxService;
    private final IInsReagentBottleService iInsReagentBottleService;
    private final IInsProjectService insProjectService;
    private final IInsProjectCodeNoService iInsProjectCodeNoService;
    private final IInsProjectReagentCodeService iInsProjectReagentCodeService;
    private final IInsMachineReagentCodeService iInsMachineReagentCodeService;
    private final IInsProjectReagentMonthService iInsProjectReagentMonthService;
    private final IInsProjectReagentMonthDetailService iInsProjectReagentMonthDetailService;

    /**
     * 查询试剂订单记录列表
     */
    @PreAuthorize("@ss.hasPermi('product:order:list')")
    @GetMapping("/list")
    public TableDataInfo list(InsReagentOrder insReagentOrder) {
        startPage();
        LambdaQueryWrapper<InsReagentOrder> lqw = new LambdaQueryWrapper<>();
        if (insReagentOrder.getProjectId() != null) {
            lqw.eq(InsReagentOrder::getProjectId, insReagentOrder.getProjectId());
        }
        if (StringUtils.isNotBlank(insReagentOrder.getCheckState())) {
            lqw.eq(InsReagentOrder::getCheckState, insReagentOrder.getCheckState());
        }
        if (StringUtils.isNotBlank(insReagentOrder.getOrderState())) {
            lqw.eq(InsReagentOrder::getOrderState, insReagentOrder.getOrderState());
        }
        if (insReagentOrder.getRecordTime() != null) {
            //一天的开始，结果：2017-03-01 00:00:00
            Date beginOfDay = DateUtil.beginOfDay(insReagentOrder.getRecordTime());
            //一天的结束，结果：2017-03-01 23:59:59
            Date endOfDay = DateUtil.endOfDay(insReagentOrder.getRecordTime());
            lqw.between(InsReagentOrder::getRecordTime, beginOfDay, endOfDay);
        }
        lqw.orderByDesc(InsReagentOrder::getOrderId);
        List<InsReagentOrder> list = iInsReagentOrderService.list(lqw);
        return getDataTable(list);
    }

    /**
     * 导出试剂订单记录列表
     */
    @PreAuthorize("@ss.hasPermi('product:order:export')")
    @Log(title = "试剂订单记录", businessType = BusinessType.EXPORT)
    @GetMapping("/export")
    public AjaxResult export(InsReagentOrder insReagentOrder) {
        LambdaQueryWrapper<InsReagentOrder> lqw = new LambdaQueryWrapper<>(insReagentOrder);
        List<InsReagentOrder> list = iInsReagentOrderService.list(lqw);
        ExcelUtil<InsReagentOrder> util = new ExcelUtil<>(InsReagentOrder.class);
        return util.exportExcel(list, "order");
    }

    /**
     * 获取试剂订单记录详细信息
     */
    @PreAuthorize("@ss.hasPermi('product:order:query')")
    @GetMapping(value = "/{orderId}")
    public AjaxResult getInfo(@PathVariable("orderId") Integer orderId) {
        InsReagentOrder reagentOrder = iInsReagentOrderService.getById(orderId);

        InsReagentOrderDTO reagentOrderDTO = new InsReagentOrderDTO();
        BeanUtils.copyProperties(reagentOrder, reagentOrderDTO);

        LambdaQueryWrapper<InsReagentOrderList> lqw = new LambdaQueryWrapper<>();
        lqw.eq(InsReagentOrderList::getOrderId, orderId);
        lqw.orderByDesc(InsReagentOrderList::getPriority);

        List<InsReagentOrderList> reagentOrderLists = iInsReagentOrderListService.list(lqw);
        List<InsReagentOrderListDTO> reagentOrderListDTOS = new ArrayList<>();

        for (InsReagentOrderList reagentOrderList : reagentOrderLists) {
            LambdaQueryWrapper<InsReagentOrderListDetail> lqw2 = new LambdaQueryWrapper<>();
            lqw2.eq(InsReagentOrderListDetail::getOrderListId, reagentOrderList.getOrderListId());
            InsReagentOrderListDTO reagentOrderListDTO = new InsReagentOrderListDTO();
            BeanUtils.copyProperties(reagentOrderList, reagentOrderListDTO);

            InsReagentForm insReagentForm = iInsReagentFormService.getById(reagentOrderList.getReagentFormId());
            InsReagentFormDTO insReagentFormDTO = new InsReagentFormDTO();
            BeanUtils.copyProperties(insReagentForm, insReagentFormDTO);

            LambdaQueryWrapper<InsReagentFormDetail> lqw3 = new LambdaQueryWrapper<>();
            lqw3.eq(InsReagentFormDetail::getReagentFormId, reagentOrderList.getReagentFormId());
            List<InsReagentFormDetail> insReagentFormDetailList = iInsReagentFormDetailService.list(lqw3);
            insReagentFormDTO.setInsReagentFormDetailList(insReagentFormDetailList);

            reagentOrderListDTO.setInsReagentFormDTO(insReagentFormDTO);

            List<InsReagentOrderListDetail> reagentOrderListDetails = iInsReagentOrderListDetailService.list(lqw2);
            reagentOrderListDTO.setReagentOrderListDetails(reagentOrderListDetails);
            reagentOrderListDTOS.add(reagentOrderListDTO);
        }
        reagentOrderDTO.setReagentOrderLists(reagentOrderListDTOS);

        return AjaxResult.success(reagentOrderDTO);
    }

    /**
     * 新增试剂订单记录
     */
    @PreAuthorize("@ss.hasPermi('product:order:add')")
    @Log(title = "试剂订单记录", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody InsReagentOrder insReagentOrder) {
        boolean save = iInsReagentOrderService.save(insReagentOrder);
        return save ? AjaxResult.success(insReagentOrder) : AjaxResult.error("保存失败");
    }

    /**
     * 修改试剂订单记录
     */
    @PreAuthorize("@ss.hasPermi('product:order:edit')")
    @Log(title = "试剂订单记录", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody InsReagentOrder insReagentOrder) {
        return toAjax(iInsReagentOrderService.updateById(insReagentOrder) ? 1 : 0);
    }

    /**
     * 删除试剂订单记录
     */
    @PreAuthorize("@ss.hasPermi('product:order:remove')")
    @Log(title = "试剂订单记录", businessType = BusinessType.DELETE)
    @DeleteMapping("/{orderIds}")
    public AjaxResult remove(@PathVariable Integer[] orderIds) {
        return toAjax(iInsReagentOrderService.removeByIds(Arrays.asList(orderIds)) ? 1 : 0);
    }

    /**
     * 试剂订单标签生成
     */
    @PreAuthorize("@ss.hasPermi('product:order:addReagentCode')")
    @Log(title = "试剂订单标签生成", businessType = BusinessType.INSERT)
    @PostMapping("/addReagentCode")
    public AjaxResult addReagentCode(@RequestBody InsReagentOrderDTO reagentOrderDTO) {
        Integer orderId = reagentOrderDTO.getOrderId();
        String projectCode = reagentOrderDTO.getProjectCode();

        InsProject project = insProjectService.getById(reagentOrderDTO.getProjectId());

        projectCode = projectCode.length() < 4 ? projectCode + " " : projectCode;
        String testMethod = reagentOrderDTO.getTestMethod();
        DateTime dateTime = DateUtil.date(reagentOrderDTO.getRequirePacTime());
        String year = Integer.toString(dateTime.year()).substring(2);
        String month = addZero(dateTime.monthStartFromOne(), 2);
        String createTime = DateUtil.format(reagentOrderDTO.getCreateTime(), "yyyyMMdd");
        String expireDate = DateUtil.format(reagentOrderDTO.getExpireDate(), "yyyy-MM-dd");

        List<InsReagentBox> reagentBoxList = new ArrayList<>();
        List<InsReagentBottle> reagentBottleList = new ArrayList<>();

        List<InsReagentOrderListDTO> reagentOrderLists = reagentOrderDTO.getReagentOrderLists();

        LambdaQueryWrapper<InsReagentOrderListDetail> lqw2 = new LambdaQueryWrapper<>();
        lqw2.eq(InsReagentOrderListDetail::getOrderId, orderId);
        lqw2.in(InsReagentOrderListDetail::getOrderListId, reagentOrderLists.stream().map(InsReagentOrderListDTO::getOrderListId).collect(Collectors.toList()));
        List<InsReagentOrderListDetail> reagentOrderListDetails = iInsReagentOrderListDetailService.list(lqw2);


        for (InsReagentOrderListDetail reagentOrderListDetail : reagentOrderListDetails) {
            String machineType = iSysDictDataService.selectDictLabel("machine_type", reagentOrderListDetail.getMachineType());
            Integer amount = reagentOrderListDetail.getAmount();
            Integer orderListId = reagentOrderListDetail.getOrderListId();
            String createTime2 = DateUtil.format(reagentOrderListDetail.getCreateTime(), "yyyyMMdd");
            String expireDate2 = DateUtil.format(reagentOrderListDetail.getExpireDate(), "yyyy-MM-dd");
            Integer reagentFormId = reagentOrderListDetail.getReagentFormId();
            String reagentType = reagentOrderListDetail.getReagentType();
            LambdaQueryWrapper<InsReagentFormDetail> insReagentFormDetailLambdaQueryWrapper = new LambdaQueryWrapper<>();
            insReagentFormDetailLambdaQueryWrapper.eq(InsReagentFormDetail::getReagentFormId, reagentFormId);
            insReagentFormDetailLambdaQueryWrapper.eq(InsReagentFormDetail::getReagentType, reagentType);
            InsReagentFormDetail reagentFormDetail = iInsReagentFormDetailService.getOne(insReagentFormDetailLambdaQueryWrapper);
            if (reagentFormDetail == null || !reagentFormDetail.getBottleTagPrint()) {
                continue;
            }
            Integer bottleSeqNo = reagentFormDetail.getSeqNo();
            Integer bottleBarcodeTagTempCodeno = reagentFormDetail.getBottleBarcodeTagTempCodeno();
            InsReagentForm reagentForm = iInsReagentFormService.getById(reagentOrderListDetail.getReagentFormId());
            Date lastPackageTime = reagentForm.getLastPackageTime();
            boolean resetFlag = isResetFlag(reagentOrderDTO, lastPackageTime);
            if (resetFlag) {
                bottleSeqNo = 1;
            }
            //生成试剂瓶记录
            for (int i = 0; i <= amount; i++) {
                String[] barcodeArr = getBottleBarcode(machineType, bottleSeqNo, resetFlag, reagentOrderListDetail, project, reagentFormDetail);
                InsReagentBottle reagentBottle = new InsReagentBottle();
                reagentBottle.setOrderListId(orderListId);
                reagentBottle.setOrderId(orderId);
                reagentBottle.setProjectCode(projectCode);
                reagentBottle.setProjectName(reagentOrderDTO.getProjectName());
                reagentBottle.setTestMethod(testMethod);
                reagentBottle.setReagentVolume(reagentOrderListDetail.getReagentVolume());
                reagentBottle.setCreateTime(createTime2);
                reagentBottle.setExpireDate(expireDate2);
                reagentBottle.setLotNo(reagentOrderListDetail.getLotNo());
                reagentBottle.setReagentType(reagentType);
                reagentBottle.setCeFlag(reagentOrderDTO.getCeFlag());
                reagentBottle.setMachineType(machineType);
                reagentBottle.setBarcodeOriginal(barcodeArr[0]);
                reagentBottle.setBarcode(barcodeArr[1]);

                reagentBottle.setBottleBarcodeTagTempCodeno(bottleBarcodeTagTempCodeno);
                reagentBottle.setSpecUnit(reagentForm.getSpecUnit());
                if (i == amount) {
                    reagentBottle.setReserveFlag(true);
                }
                bottleSeqNo += 1;
                reagentBottleList.add(reagentBottle);
            }
            reagentFormDetail.setSeqNo(bottleSeqNo);
            iInsReagentFormDetailService.updateById(reagentFormDetail);
        }

        for (InsReagentOrderListDTO reagentOrderListDTO : reagentOrderLists) {
            Integer amount = reagentOrderListDTO.getAmount();
            Long orderListId = reagentOrderListDTO.getOrderListId();
            String machineType = iSysDictDataService.selectDictLabel("machine_type", reagentOrderListDTO.getMachineType());
            InsReagentForm reagentForm = iInsReagentFormService.getById(reagentOrderListDTO.getReagentFormId());
            if (reagentForm == null || !reagentForm.getBoxTagPrint()) {
                continue;
            }
            Integer boxSeqNo = reagentForm.getBoxSeqNo();
            Date lastPackageTime = reagentForm.getLastPackageTime();
            boolean resetFlag = isResetFlag(reagentOrderDTO, lastPackageTime);

            if (resetFlag) {
                boxSeqNo = 1;
            }
            //生成试剂盒记录
            for (int i = 0; i <= amount; i++) {
                String seq = addZero(boxSeqNo, 5);
                String barcode = projectCode + year + month + seq;
                InsReagentBox reagentBox = new InsReagentBox();
                reagentBox.setOrderListId(Integer.valueOf(orderListId.toString()));
                reagentBox.setOrderId(orderId);
                reagentBox.setMachineType(machineType);
                reagentBox.setProjectCode(reagentOrderDTO.getProjectCode());
                reagentBox.setProjectName(reagentOrderDTO.getProjectName());
                reagentBox.setTestMethod(testMethod);
                reagentBox.setItemNo(reagentOrderListDTO.getItemNo());
                reagentBox.setReagentSpec(reagentOrderListDTO.getReagentSpec());
                reagentBox.setCreateTime(createTime);
                reagentBox.setExpireDate(expireDate);
                reagentBox.setLotNo(reagentOrderDTO.getLotNumber());
                reagentBox.setBarcode(barcode);
                reagentBox.setRegistrationNo(reagentOrderDTO.getRegistrationNo());
                reagentBox.setProductionLicenseNo(reagentOrderDTO.getProductionLicenseNo());
                reagentBox.setCeFlag(reagentOrderDTO.getCeFlag());
                reagentBox.setBoxBarcodeTagTempCodeno(reagentForm.getBoxBarcodeTagTempCodeno());
                reagentBox.setSpecPrefix(reagentForm.getSpecPrefix());
                reagentBox.setSpecUnit(reagentForm.getSpecUnit());

                if (i == amount) {
                    reagentBox.setReserveFlag(true);
                }
                boxSeqNo += 1;
                reagentBoxList.add(reagentBox);
            }
            //保存更新后的序列号到数据库
            reagentForm.setBoxSeqNo(boxSeqNo);
            reagentForm.setLastPackageTime(reagentOrderDTO.getRequirePacTime());
            iInsReagentFormService.updateById(reagentForm);
            //下单为相同机型时可能会出现重复相加
            if (resetFlag) {
                LambdaQueryWrapper<InsProjectCodeNo> lqw3 = new LambdaQueryWrapper<>();
                lqw3.eq(InsProjectCodeNo::getProjectId, project.getProjectId());
                lqw3.eq(InsProjectCodeNo::getMachineType, reagentOrderListDTO.getMachineType());
                InsProjectCodeNo projectCodeNo = iInsProjectCodeNoService.getOne(lqw3);
                if (projectCodeNo != null) {
                    projectCodeNo.setLotBarcode(projectCodeNo.getLotBarcode() + 4);
                    iInsProjectCodeNoService.updateById(projectCodeNo);
                }
            }
        }
        reagentOrderLists.forEach(item -> {
            item.setState(true);
            iInsReagentOrderListService.saveOrUpdate(item);
        });
        boolean saveBatch1 = iInsReagentBoxService.saveBatch(reagentBoxList);

        boolean saveBatch2 = iInsReagentBottleService.saveBatch(reagentBottleList);
        //已生成条码
        reagentOrderDTO.setOrderState("3");
        iInsReagentOrderService.updateById(reagentOrderDTO);
        return saveBatch1 && saveBatch2 ? AjaxResult.success() : AjaxResult.error();
    }

    /**
     * 试剂订单生产量录入
     */
    @PreAuthorize("@ss.hasPermi('product:order:updateReagentOrderDTO')")
    @Log(title = "试剂订单生产量录入", businessType = BusinessType.UPDATE)
    @PutMapping("/updateReagentOrderDTO")
    public AjaxResult updateReagentOrderDTO(@RequestBody InsReagentOrderDTO reagentOrderDTO) {
        List<InsReagentOrderListDTO> reagentOrderLists = reagentOrderDTO.getReagentOrderLists();
        List<InsReagentOrderList> orderLists = new ArrayList<>();
        for (InsReagentOrderListDTO reagentOrderList : reagentOrderLists) {
            InsReagentOrderList insReagentOrderList = new InsReagentOrderList();
            BeanUtils.copyProperties(reagentOrderList, insReagentOrderList);
            orderLists.add(insReagentOrderList);
            List<InsReagentOrderListDetail> reagentOrderListDetails = reagentOrderList.getReagentOrderListDetails();
            iInsReagentOrderListDetailService.updateBatchById(reagentOrderListDetails, reagentOrderListDetails.size());
        }
        iInsReagentOrderListService.updateBatchById(orderLists, orderLists.size());
        return AjaxResult.success(reagentOrderDTO);
    }

    /**
     * 根据机型获取瓶贴条形码内容
     */
    private String[] getBottleBarcode(String machineType, Integer bottleSeqNo, boolean resetFlag, InsReagentOrderListDetail reagentOrderListDetail, InsProject project, InsReagentFormDetail reagentFormDetail) {
        String[] barcodeArr = new String[2];
        switch (machineType) {
            case "PA1500":
            case "1500":
                barcodeArr = get1500Barcode(bottleSeqNo, reagentOrderListDetail, project, reagentFormDetail);
                break;
            case "wp400":
                barcodeArr = getWP400Barcode(bottleSeqNo, reagentOrderListDetail, project, reagentFormDetail);
                break;
            case "杜邦":
            case "杜邦开放":
            case "杜邦封闭":
                barcodeArr = getDuBangKaiFangBarcode(bottleSeqNo, resetFlag, reagentOrderListDetail, project);
                break;
            case "D2400":
            case "7600D":
            case "D2400/7600D":
                barcodeArr = getD2400And7600DBarcode(bottleSeqNo, resetFlag, reagentOrderListDetail, project);
                break;
            case "西门子":
            case "Siemens":
                barcodeArr = getSiemensBarcode(bottleSeqNo, reagentOrderListDetail, project);
                break;
            case "3500":
            case "日立3500":
                barcodeArr = get3500Barcode(bottleSeqNo, resetFlag, reagentOrderListDetail, project);
                break;
            case "Modular":
            case "Modular 封闭":
            case "Modular 开放":
                barcodeArr = getModularBarcode(bottleSeqNo, resetFlag, reagentOrderListDetail, project);
                break;
            case "西门子Atellica":
            case "阿特丽卡":
            case "Atellica":
                barcodeArr = getSiemensAtellicaBarcode(bottleSeqNo, reagentOrderListDetail, project);
                break;
            case "Sysmex":
            case "sysmex":
                barcodeArr = getSysmexBarcode(reagentOrderListDetail, project);
                break;
            default:
                String seq = addZero(bottleSeqNo, 5);
                barcodeArr[0] = project.getShortName() + reagentFormDetail.getReagentType() + seq;
                barcodeArr[1] = project.getShortName() + reagentFormDetail.getReagentType() + seq;
        }
        return barcodeArr;
    }

    private String[] get3500Barcode(Integer bottleSeqNo, boolean resetFlag, InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        String[] barcodeArr = new String[2];
        StringBuilder barcodeOriginal = new StringBuilder();

        InsMachineReagentCode machineReagentCode = getInsMachineReagentCode(reagentOrderListDetail);

        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);

        Date expireDate = reagentOrderListDetail.getExpireDate();
        String year = Integer.toString(DateUtil.year(expireDate)).substring(3);

        int expireWeekOfYear = DateUtil.weekOfYear(expireDate);

        if (projectCodeNo == null || projectCodeNo.getLotBarcode() == null || StringUtils.isBlank(projectCodeNo.getCodeNo())) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        Integer lotBarcode = projectCodeNo.getLotBarcode();
        if (resetFlag) {
            lotBarcode += 4;
        }
        // 项目代码：5位
        barcodeOriginal.append(addZero(projectCodeNo.getCodeNo(), 5))
                //试剂瓶大小(其中2:代表5ml玻璃试剂瓶;3代表15ml玻璃试剂瓶;4代表25ml玻璃试剂瓶 1位
                .append(reagentOrderListDetail.getBottleTypeSerialNo())
                // 试剂位R1或R2 1位  R1:1 R2:3
                .append(machineReagentCode != null
                        ? machineReagentCode.getCodeNo() : reagentOrderListDetail.getReagentType())
                //效期年 1位
                .append(year)
                //效期周 4位
                .append(expireWeekOfYear)
                //批号3位
                .append(addZero(lotBarcode, 3))
                //序列号4位
                .append(addZero(bottleSeqNo, 4));
        //校验码 1位
        //.append("J");
        barcodeArr[0] = barcodeOriginal.toString() + getInterleaved2Of5(barcodeOriginal.toString());
        //条码生成标签时由打印标签软件自动计算mod10
        barcodeArr[1] = barcodeOriginal.toString();
        return barcodeArr;
    }

    /**
     * 获取Modular试剂瓶贴条码
     */
    private String[] getModularBarcode(Integer bottleSeqNo, boolean resetFlag, InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        String[] barcodeArr = new String[2];
        Date expireDate = reagentOrderListDetail.getExpireDate();
        String year = Integer.toString(DateUtil.year(expireDate)).substring(3);
        int month = DateUtil.date(expireDate).monthStartFromOne();
        StringBuilder barcodeOriginal = new StringBuilder();
        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);
        if (projectCodeNo == null || projectCodeNo.getLotBarcode() == null || StringUtils.isBlank(projectCodeNo.getCodeNo())) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        Integer lotBarcode = projectCodeNo.getLotBarcode();
        if (resetFlag) {
            lotBarcode += 4;
        }
        InsProjectReagentMonth projectReagentMonth = getProjectReagentMonth(reagentOrderListDetail, project);

        InsProjectReagentMonthDetail projectReagentMonthDetail = getProjectReagentMonthDetail(month, projectReagentMonth);

        //产品代码3位
        barcodeOriginal.append(addZero(projectCodeNo.getCodeNo(), 3))
                //产品批号6位
                .append(addZero(lotBarcode, 6))
                //序列号5位
                .append(addZero(bottleSeqNo, 5))
                //对应的月份编号3位
                .append(addZero(projectReagentMonthDetail.getCodeNo(), 3))
                //效期年份
                .append(year);
        barcodeArr[0] = barcodeOriginal.toString();
        barcodeArr[1] = barcodeOriginal.toString();
        return barcodeArr;
    }

    private InsProjectReagentMonthDetail getProjectReagentMonthDetail(int month, InsProjectReagentMonth projectReagentMonth) {
        LambdaQueryWrapper<InsProjectReagentMonthDetail> lqw = new LambdaQueryWrapper<>();
        lqw.eq(InsProjectReagentMonthDetail::getRandomUuid, projectReagentMonth.getRandomUuid());
        lqw.eq(InsProjectReagentMonthDetail::getMonth, month);
        return iInsProjectReagentMonthDetailService.getOne(lqw);
    }

    private InsProjectReagentMonth getProjectReagentMonth(InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        LambdaQueryWrapper<InsProjectReagentMonth> lqw = new LambdaQueryWrapper<>();
        lqw.eq(InsProjectReagentMonth::getProjectId, project.getProjectId());
        lqw.eq(InsProjectReagentMonth::getMachineType, reagentOrderListDetail.getMachineType());
        lqw.eq(InsProjectReagentMonth::getReagentType, reagentOrderListDetail.getReagentType());
        return iInsProjectReagentMonthService.getOne(lqw);
    }

    /**
     * 获取sysmex瓶贴
     */
    private String[] getSysmexBarcode(InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        String[] barcodeArr = new String[2];
        StringBuilder barcodeOriginal = new StringBuilder();
        /*
         * 试剂代码：4位
         * D-Dimer(R1:5840,R2:5841)
         * ATIII(R1:5850,R2:5851)
         * FDP(R1:5860,R2:5861)
         */
        InsProjectReagentCode projectReagent = getInsProjectReagentCode(reagentOrderListDetail, project);
        if (projectReagent == null || StringUtils.isBlank(projectReagent.getCodeNo())) {
            throw new RuntimeException("未找到产品试剂组成信息，请先录入，再重新生成标签");
        }
        barcodeOriginal.append(addZero(projectReagent.getCodeNo(), 4))
                //批号：05 2位
                .append("05")
                //试剂瓶大小(其中2:代表5ml玻璃试剂瓶;3代表15ml玻璃试剂瓶;4代表25ml玻璃试剂瓶 1位
                .append(reagentOrderListDetail.getBottleTypeSerialNo());
        //校验码 1位
//                .append("J");
        barcodeArr[0] = barcodeOriginal.toString() + getInterleaved2Of5(barcodeOriginal.toString());
        //条码生成标签时由打印标签软件自动计算mod10
        barcodeArr[1] = barcodeOriginal.toString();
        return barcodeArr;
    }

    /**
     * 阿特丽卡瓶贴条码
     */
    private String[] getSiemensAtellicaBarcode(Integer bottleSeqNo, InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        String[] barcodeArr = new String[2];
        StringBuilder barcodeOriginal = new StringBuilder();
        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);
        if (projectCodeNo == null) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        InsMachineReagentCode machineReagentCode = getInsMachineReagentCode(reagentOrderListDetail);
        DateTime createTime = DateUtil.date(reagentOrderListDetail.getCreateTime());
        DateTime expireDate = DateUtil.date(reagentOrderListDetail.getExpireDate());
        String accessCode = projectCodeNo.getCloseAccessFlag() ? projectCodeNo.getCloseAccessCode() : "0000";
        //试剂批号 1-2位为生产年份，3-4位为生产月份，5-6位为生产日期 （如2019-07-03，则编写成190703）=》6位
        barcodeOriginal.append(Integer.toString(createTime.year()).substring(2))
                .append(addZero(createTime.monthStartFromOne(), 2))
                .append(addZero(createTime.dayOfMonth(), 2))
                // 试剂位R1或R2   R1:(10)  R2:(20)=>2位
                .append(machineReagentCode != null
                        ? machineReagentCode.getCodeNo() : Integer.parseInt(reagentOrderListDetail.getReagentType()) * 10)
                //通道=》4位
                .append(addSpace(accessCode, 4))
                //试剂批号 13-14位为效期年份，15-16位为效期月份，17-18位为效期日 （如2021-09-05，则编写成210905 =》6位
                .append(Integer.toString(expireDate.year()).substring(2))
                .append(addZero(expireDate.monthStartFromOne(), 2))
                .append(addZero(expireDate.dayOfMonth(), 2))
                //序列号5位
                .append(addZero(bottleSeqNo, 5));
        barcodeArr[0] = barcodeOriginal.toString();
        barcodeArr[1] = barcodeOriginal.toString();
        return barcodeArr;
    }

    /**
     * 获取西门子试剂条码
     */
    private String[] getSiemensBarcode(Integer bottleSeqNo, InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        String[] barcodeArr = new String[2];
        Date expireDate = reagentOrderListDetail.getExpireDate();
        int numYear = DateUtil.year(expireDate);
        int createYear = DateUtil.year(reagentOrderListDetail.getCreateTime());
        String expireYear = Integer.toString(numYear).substring(3);
        int expireWeekOfYear = DateUtil.weekOfYear(expireDate);
        int createWeekOfYear = DateUtil.weekOfYear(reagentOrderListDetail.getCreateTime());

        //产品代码
        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);
        if (projectCodeNo == null || StringUtils.isBlank(projectCodeNo.getCodeNo())) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        InsMachineReagentCode machineReagentCode = getInsMachineReagentCode(reagentOrderListDetail);

        StringBuilder barcodeOriginal = new StringBuilder();
        //产品代码5位
        barcodeOriginal.append(addZero(projectCodeNo.getCodeNo(), 5))
                //试剂瓶大小(其中2:代表20ml方管;3代表70ml扁瓶;1代表30ml扁瓶) 1位
                .append(reagentOrderListDetail.getBottleTypeSerialNo())
                //试剂位(R1:1;R2:3) 1位
                .append(machineReagentCode != null
                        ? machineReagentCode.getCodeNo() : ("2".equals(reagentOrderListDetail.getReagentType())
                        ? "3" : reagentOrderListDetail.getReagentType()))
                //有效期(年份+第几周) 1位年 2位周
                .append(expireYear)
                .append(addZero(expireWeekOfYear, 2))
                //(按生产年份-5+第几周)
                .append(Integer.toString(createYear - 5).substring(3))
                .append(addZero(createWeekOfYear, 2))
                //序列号4位
                .append(addZero(bottleSeqNo, 4));
        //校验码 1位
//                .append("J");
        barcodeArr[0] = barcodeOriginal.toString() + getInterleaved2Of5(barcodeOriginal.toString());
        //条码生成标签时由打印标签软件自动计算mod10
        barcodeArr[1] = barcodeOriginal.toString();
        return barcodeArr;
    }

    /**
     * 获取2400和7600D瓶贴条码
     */
    private String[] getD2400And7600DBarcode(Integer bottleSeqNo, boolean resetFlag, InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        String[] barcodeArr = new String[2];
        Date expireDate = reagentOrderListDetail.getExpireDate();
        int numYear = DateUtil.year(expireDate);
        String year = Integer.toString(numYear).substring(3);
        int weekOfYear = DateUtil.weekOfYear(expireDate);
        //产品代码
        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);
        if (projectCodeNo == null || projectCodeNo.getLotBarcode() == null || StringUtils.isBlank(projectCodeNo.getCodeNo())) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        //条码批号
        Integer lotBarcode = projectCodeNo.getLotBarcode();
        if (resetFlag) {
            lotBarcode += 4;
        }
        InsMachineReagentCode machineReagentCode = getInsMachineReagentCode(reagentOrderListDetail);

        StringBuilder barcodeOriginal = new StringBuilder();
        //品名编号；如ALT:106 3位
        barcodeOriginal.append(addZero(projectCodeNo.getCodeNo(), 3))
                //批号，不同批次打印批号不同，R1与R2同一批号
                .append(addZero(lotBarcode, 6))
                //序列号 5位
                .append(addZero(bottleSeqNo, 5))
                //瓶子大小，03（70ml)、04（130ml)、05（290ml)、06（330ml)、07（720ml) 2位
                .append(addZero(reagentOrderListDetail.getBottleTypeSerialNo(), 2))
                //1代表R1，2/3代表R2
                .append(machineReagentCode != null ? machineReagentCode.getCodeNo() : reagentOrderListDetail.getReagentType())
                //效期中的第几周；如：243/7=34.7，则为35周
                .append(addZero(weekOfYear, 2))
                //效期年份；如效期为2018年，数字则为8 1位
                .append(year);
        barcodeArr[0] = barcodeOriginal.toString();
        barcodeArr[1] = barcodeOriginal.toString();
        return barcodeArr;
    }

    /**
     * 获取产品试剂代码信息
     *
     * @param reagentOrderListDetail
     * @param project
     * @return
     */
    private InsProjectReagentCode getInsProjectReagentCode(InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        LambdaQueryWrapper<InsProjectReagentCode> lqw2 = new LambdaQueryWrapper<>();
        lqw2.eq(InsProjectReagentCode::getProjectId, project.getProjectId());
        lqw2.eq(InsProjectReagentCode::getMachineType, reagentOrderListDetail.getMachineType());
        lqw2.eq(InsProjectReagentCode::getReagentType, reagentOrderListDetail.getReagentType());
        return iInsProjectReagentCodeService.getOne(lqw2);
    }

    /**
     * 获取机型试剂代码信息
     *
     * @param reagentOrderListDetail
     * @return
     */
    private InsMachineReagentCode getInsMachineReagentCode(InsReagentOrderListDetail reagentOrderListDetail) {
        LambdaQueryWrapper<InsMachineReagentCode> lqw2 = new LambdaQueryWrapper<>();
        lqw2.eq(InsMachineReagentCode::getMachineType, reagentOrderListDetail.getMachineType());
        lqw2.eq(InsMachineReagentCode::getReagentType, reagentOrderListDetail.getReagentType());
        return iInsMachineReagentCodeService.getOne(lqw2);
    }

    /**
     * 获取机器产品代码和条码批号及开放通道信息
     *
     * @param reagentOrderListDetail
     * @param project
     * @return
     */
    private InsProjectCodeNo getInsProjectCodeNo(InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {
        //产品代码
        LambdaQueryWrapper<InsProjectCodeNo> lqw = new LambdaQueryWrapper<>();
        lqw.eq(InsProjectCodeNo::getProjectId, project.getProjectId());
        lqw.eq(InsProjectCodeNo::getMachineType, reagentOrderListDetail.getMachineType());
        return iInsProjectCodeNoService.getOne(lqw);
    }

    /**
     * 获取杜邦开放的瓶贴条码
     *
     * @return barcode
     */
    private String[] getDuBangKaiFangBarcode(Integer bottleSeqNo, boolean resetFlag, InsReagentOrderListDetail reagentOrderListDetail, InsProject project) {

        String[] barcodeArr = new String[2];
        Date expireDate = reagentOrderListDetail.getExpireDate();
        int numYear = DateUtil.year(expireDate);
        String year = Integer.toString(numYear).substring(3);
        int dayOfYear = getDayOfYear(expireDate);
        StringBuilder barcodeOriginal = new StringBuilder();
        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);
        if (projectCodeNo == null || projectCodeNo.getLotBarcode() == null) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        //条码批号
        Integer lotBarcode = projectCodeNo.getLotBarcode();
        if (resetFlag) {
            lotBarcode += 4;
        }
        //X大写表示开放通道
        barcodeOriginal.append("X")
                //产品名称缩写，不足3位用空格补足
                .append(addSpace(project.getName(), 3))
                //空格1位
                .append(" ")
                //二位英文字母
                .append(addSpace(project.getShortName(), 2))
                //表示到期的年份；如2018年到期，用8表示
                .append(year)
                //表示到期的日期：如每年的第204天到期，用204表示
                .append(addZero(dayOfYear, 3))
                //序列号 5位
                .append(addZero(bottleSeqNo, 5))
                //校验码 3位==>条码批号，每更换批号时+4
                .append(addZero(lotBarcode, 3));
        //mod43校验位
        //原码有mod43的校验字符
        barcodeArr[0] = barcodeOriginal.toString() + getCode39Mod43(barcodeOriginal.toString());
        //条码生成标签时由打印标签软件自动计算mod43
        barcodeArr[1] = barcodeOriginal.toString();
        return barcodeArr;
    }

    /**
     * 获取1500的瓶贴条码
     *
     * @return barcode
     */
    private String[] get1500Barcode(Integer bottleSeqNo, InsReagentOrderListDetail reagentOrderListDetail, InsProject project, InsReagentFormDetail reagentFormDetail) {
        int testCount = reagentFormDetail.getTestCount() / 10;
        String bottleTypeSerialNo = reagentOrderListDetail.getBottleTypeSerialNo();
        Date expireDate = reagentOrderListDetail.getExpireDate();
        DateTime date = DateUtil.date(expireDate);
        String year = Integer.toString(date.year()).substring(3);
        int dayOfYear = getDayOfYear(date);
//        SysDictData sysDictData = new SysDictData();
//        sysDictData.setDictType("code_book_1500");
//        List<SysDictData> list = iSysDictDataService.selectDictDataList(sysDictData);
//        Map<Integer, String> map = new HashMap<>(list.size());
//        for (SysDictData dictData : list) {
//            map.put(Integer.valueOf(dictData.getDictLabel()), dictData.getDictValue());
//        }
//        String[] newArr = new String[10];
//        int num = (int) (Math.random() * 1000);
//        int start = num % 19;
//        for (int i = 0; i < 10; i++) {
//            int wei = start + i;
//            newArr[i] = map.get(wei % 19);
//        }
        StringBuilder barcodeOriginal = new StringBuilder();
        StringBuilder barcodeOutput = new StringBuilder();
        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);
        if (projectCodeNo == null || StringUtils.isBlank(projectCodeNo.getCodeNo())) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        InsMachineReagentCode machineReagentCode = getInsMachineReagentCode(reagentOrderListDetail);
        //3位   名称  （产品代码，代表什么产品）
        barcodeOriginal.append(addZero(projectCodeNo.getCodeNo(), 3))
                //4位    批号（效期）：年（1位）+日（3位）
                .append(year)
                .append(addZero(dayOfYear, 3))
                //4位   序列号
                .append(addZero(bottleSeqNo, 4))
                //1位      R1 R2  R3
                .append(machineReagentCode != null ? machineReagentCode.getCodeNo() : reagentFormDetail.getReagentType())
                //1位   瓶子大小编号
                .append(bottleTypeSerialNo)
                //2位     规格（测试数）：需要有测试数记忆
                .append(addZero(testCount, 2));

        // 此处密钥如果有非ASCII字符，考虑编码
        byte[] key = "PA1500".getBytes();
        HMac mac = new HMac(HmacAlgorithm.HmacMD5, key);

        String macHex = mac.digestHex(barcodeOriginal.toString());
        String checkCode = macHex.substring(9, 12);

//        IntStream intStream = barcodeOriginal.chars();
//        intStream.forEach(ch -> barcodeOutput.append(newArr[Character.getNumericValue(ch)]));
        //3位   校验码
        barcodeOriginal.append(checkCode);
        barcodeOutput.append(barcodeOriginal);
//        barcodeOutput.append(addZero(num, 3));
//        barcodeOriginal.append(addZero(num, 3));
        String[] arr = new String[2];
        //原码
        arr[0] = barcodeOriginal.toString();
        //混淆码
        arr[1] = barcodeOutput.toString();
        return arr;
    }
    /**
     * 获取wp400的瓶贴条码
     *
     * @return barcode
     */
    private String[] getWP400Barcode(Integer bottleSeqNo, InsReagentOrderListDetail reagentOrderListDetail, InsProject project, InsReagentFormDetail reagentFormDetail) {
        int testCount = reagentFormDetail.getTestCount() / 10;
        String bottleTypeSerialNo = reagentOrderListDetail.getBottleTypeSerialNo();
        Date expireDate = reagentOrderListDetail.getExpireDate();
        DateTime date = DateUtil.date(expireDate);
        String year = Integer.toString(date.year()).substring(3);
        int dayOfYear = getDayOfYear(date);
        StringBuilder barcodeOriginal = new StringBuilder();
        StringBuilder barcodeOutput = new StringBuilder();
        InsProjectCodeNo projectCodeNo = getInsProjectCodeNo(reagentOrderListDetail, project);
        if (projectCodeNo == null || StringUtils.isBlank(projectCodeNo.getCodeNo())) {
            throw new RuntimeException("未找到产品代码信息，请先录入，再重新生成标签");
        }
        InsMachineReagentCode machineReagentCode = getInsMachineReagentCode(reagentOrderListDetail);
        //3位   名称  （产品代码，代表什么产品）
        barcodeOriginal.append(addZero(projectCodeNo.getCodeNo(), 3))
                //1位   瓶子大小编号
                .append(bottleTypeSerialNo)
                //1位      R1 R2  R3
                .append(machineReagentCode != null ? machineReagentCode.getCodeNo() : reagentFormDetail.getReagentType())
                //4位    批号（效期）：年（1位）+日（3位）
                .append(year)
                .append(addZero(dayOfYear, 3))
                //2位     规格（测试数）：需要有测试数记忆
                .append(addZero(testCount, 2))
                //5位   序列号
                .append(addZero(bottleSeqNo, 5));

        // 此处密钥如果有非ASCII字符，考虑编码
        byte[] key = "wp400".getBytes();
        HMac mac = new HMac(HmacAlgorithm.HmacMD5, key);

        String macHex = mac.digestHex(barcodeOriginal.toString());
        String checkCode = macHex.substring(9, 12);
        //3位   校验码
        barcodeOriginal.append(checkCode);
        barcodeOutput.append(barcodeOriginal);
        String[] arr = new String[2];
        //原码
        arr[0] = barcodeOriginal.toString();
        //混淆码
        arr[1] = barcodeOutput.toString();
        return arr;
    }

    private boolean isResetFlag(InsReagentOrder reagentOrder, Date lastPackageTime) {
        boolean resetFlag = false;
        if (lastPackageTime != null) {
            DateTime lastDate = DateUtil.date(lastPackageTime);
            DateTime requireDate = DateUtil.date(reagentOrder.getRequirePacTime());
            int requireMonth = requireDate.monthStartFromOne();
            int lastMonth = lastDate.monthStartFromOne();
            int intervalMonth = requireMonth - lastMonth;
            int intervalYear = requireDate.year() - lastDate.year();
            if (intervalMonth > 0 || intervalYear > 0) {
                resetFlag = true;
            }
        }
        return resetFlag;
    }

    //  计算天数
    public static int getDayOfYear(Date date) {
        Calendar cal = Calendar.getInstance();
//      将日期设置给Calendat
        cal.setTime(date);
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DATE);
//      定义累加器储存天数
        int num = 0;
//      遍历月份，求每个月份的天数和
        for (int i = 1; i < month; i++) {
            switch (i) {
//          当月为大月时累加31
                case 1:
                case 3:
                case 5:
                case 7:
                case 8:
                case 10:
                case 12:
                    num += 31;
                    break;
//          当月为二月时闰年累加29，平年累加28
                case 2:
                    boolean b = year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
                    num += b ? 29 : 28;
                    break;
                default:
                    num += 30;
                    break;
            }
        }
//      加上日
        num += day;
        return num;
    }

    /**
     * description: 使用 String.format 格式化数字，实现左侧补 0
     *
     * @param num   需要格式化的数字
     * @param digit 生成字符串长度（保留数字位数）
     * @return String
     * @author w
     * @date 2019年7月19日 下午2:14:31
     */
    public static String addZero(int num, int digit) {
        /*
         * 0：表示前面补0
         * digit：表示保留数字位数
         * d：表示参数为正数类型
         */
        return String.format("%0" + digit + "d", num);
    }

    public static String addZero(String str, int strLength) {
        int strLen = str.length();
        if (strLen < strLength) {
            StringBuilder strBuilder = new StringBuilder(str);
            while (strLen < strLength) {
                // sb.append(str).append("0");//右补0
                strBuilder.insert(0, "0")// 左补0
                // sb.append(str).append("0");//右补0
                ;
                strLen = strBuilder.length();
            }
            str = strBuilder.toString();
        }

        return str;
    }

    public static String addSpace(String str, int strLength) {
        int strLen = str.length();
        if (strLen < strLength) {
            StringBuilder strBuilder = new StringBuilder(str);
            while (strLen < strLength) {
                strBuilder.append(" ")//右补空格
                ;
                strLen = strBuilder.length();
            }
            str = strBuilder.toString();
        }

        return str;
    }

    /**
     * Code39 mod43
     */
    public static String getCode39Mod43(String barcode) {
        int subtotal = 0;
        String charSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%";
        for (int i = 0; i < barcode.length(); i++) {
            subtotal += charSet.indexOf(barcode.substring(i, i + 1));
        }
        int mod = subtotal % 43;
        return charSet.substring(mod, mod + 1);
    }

    /**
     * Interleaved-2-of-5
     */
    public static int getInterleaved2Of5(String barcode) {
        int sumOdd = 0;
        int sumEven = 0;
        int length = barcode.length();
        int[] wei = new int[length];
        for (int i = 0; i < barcode.length(); i++) {
            wei[i] = Integer.parseInt(barcode.substring(length - i - 1, length
                    - i));// 从最末一位开始提取，每一位上的数值
        }
        for (int i = 0; i < wei.length; i++) {
            if (i % 2 == 0) {
                sumEven += wei[i];
            } else {
                sumOdd += wei[i];
            }
        }
        int sum = sumEven * 3 + sumOdd;
        return sum % 10 > 0 ? 10 - sum % 10 : 0;
    }

//    public static void main(String[] args) {
//        // 此处密钥如果有非ASCII字符，考虑编码
//        byte[] key = "PA1500".getBytes();
//        HMac mac = new HMac(HmacAlgorithm.HmacMD5, key);
//        Scanner scanner = new Scanner(System.in);
//        StringBuilder builder = new StringBuilder();
//        while (true) {
//            String next = scanner.nextLine();
//            String macHex = mac.digestHex(next);
//            String checkCode = macHex.substring(9, 12);
//            builder.append(next)
//                    .append(checkCode);
//            System.out.println(builder);
//            builder.setLength(0);
//        }
//
//    }
}
